import { httpError, Inject, Provide } from '@midwayjs/core'
import { Context } from '@midwayjs/koa'
import { InjectEntityModel } from '@midwayjs/typeorm'
import { In, Repository } from 'typeorm'

import { DeleteDTO } from '@/dto'
import { SysDeptEntity } from '@/entity'
import { StateService } from '@/service'
import { TransformUtil } from '@/util'

import { CreateDeptDTO, FindDeptListDTO, UpdateDeptDTO } from './dept.dto'

@Provide()
export class DeptService {
  @Inject()
  ctx: Context

  @InjectEntityModel(SysDeptEntity)
  deptModel: Repository<SysDeptEntity>

  async handleFindList(dto: FindDeptListDTO) {
    const { ...where } = dto

    return await this.deptModel.find({
      where: {
        delFlag: '0',
        ...where
      },
      order: {
        orderNum: 'ASC'
      }
    })
  }

  async handleFindTree() {
    const data = await this.deptModel.find({
      where: { delFlag: '0', status: '0' }
    })

    return TransformUtil.listToTree(data, {
      title: 'deptName',
      key: 'deptId',
      parentKey: 'parentId'
    })
  }

  async handleCreate(dto: CreateDeptDTO) {
    const stateService = await this.ctx.requestContext.getAsync(StateService)

    const jwtPayload = stateService.getJwtPayload()

    const parentDept = await this.deptModel.findOne({
      where: { deptId: dto.parentId }
    })

    if (!parentDept) {
      this.ctx.throw(new httpError.BadRequestError('上级部门不存在'))
    }

    const dept = new SysDeptEntity()

    Object.assign<any, any, Partial<SysDeptEntity>>(dept, dto, {
      ancestors: `${parentDept.ancestors},${parentDept.deptId}`,
      createBy: jwtPayload.userName
    })

    await this.deptModel.save(dept)
  }

  async handleDelete(dto: DeleteDTO) {
    const { ids } = dto

    const list = await this.deptModel.find({
      relations: { roles: true },
      where: { deptId: In(ids) }
    })

    for (const dept of list) {
      dept.delFlag = '2'
      dept.roles = []

      await this.deptModel.save(dept)
    }
  }

  async handleUpdate(id: string, dto: UpdateDeptDTO) {
    const stateService = await this.ctx.requestContext.getAsync(StateService)

    const jwtPayload = stateService.getJwtPayload()

    const [dept, parentDept] = await Promise.all([
      this.deptModel.findOne({ where: { deptId: id } }),
      this.deptModel.findOne({ where: { deptId: dto.parentId } })
    ])

    if (!dept) {
      this.ctx.throw(new httpError.BadRequestError('部门不存在'))
    }

    if (!parentDept) {
      this.ctx.throw(new httpError.BadRequestError('上级部门不存在'))
    }

    Object.assign<any, any, Partial<SysDeptEntity>>(dept, dto, {
      ancestors:
        dept.parentId !== dto.parentId
          ? `${parentDept.ancestors},${parentDept.deptId}`
          : dept.ancestors,
      updateBy: jwtPayload.userName
    })

    await this.deptModel.save(dept)
  }
}
